Demo notebook¶
[1]:
# This is just for convenience to retreive files
import sisl._environ
siesta_files = sisl._environ.get_environ_variable("SISL_FILES_TESTS") / "sisl" / "io" / "siesta"
The basics¶
The first thing you will need to do in order to use plots is to import them from the sisl.viz module:
[2]:
from sisl.viz import Plot
Let’s start plotting!
Why can’t I just tell the computer to plot the file?! This is the question milions of students around the world ask themselves when they get introduced to computational physics. Then time passes, and you learn to deal with it. You might even build your own scripts in an attempt to mitigate the pain. But hey:
[3]:
Plot(siesta_files / "SrTiO3.bands")
[4]:
Plot(siesta_files / "SrTiO3.RHO", axes=[0,1], nsc=[2,1,1], zsmooth='best')
See what we did there? We passed some extra arguments (axes and nsc) to get the exact plot that we want.
But how do you know which words to use?
Be patient, we will get there.
Ok, but still, you only have different scripts that plot different things. And you use this fancy
Plot()stuff to catch our attention.
Not really. In fact, what Plot() does is to initialize a plot instance. If you store it into a variable you can check for yourself.
[5]:
plot = Plot(siesta_files / "SrTiO3.RHO", axes=[0,1], nsc=[2,1,1], zsmooth="best")
plot.__class__
[5]:
sisl.viz.plotly.plots.grid.GridPlot
[6]:
plot.show("png")
Note also that it’s not exactly a Plot, but a GridPlot. This means that it will have settings and methods that are specific to this kind of plot. Settings may be found by printing the variable.
You can ``print(plot)`` to see how they look like if you really can’t wait. Here’s a cell for you, we won’t know:
[ ]:
Are you done? Good. Now if you want to make a better use of that cell do help(plot) instead. You will see a list of the mehods that are available to you in this plot. Actually we are more interested in the specific methods that this plot has, so when you reach the line:
Methods inherited from sisl.viz.plot.Plot:
you can stop reading.
Let’s try one of those!
[7]:
# We already have a plot stored
plot.scan(steps=15)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-1-838a1ab8dc4c> in <module>
1 # We already have a plot stored
----> 2 plot.scan(steps=15)
/opt/hostedtoolcache/Python/3.6.12/x64/lib/python3.6/site-packages/sisl/viz/plotly/plots/grid.py in scan(self, along, start, stop, step, num, breakpoints, mode, animation_kwargs, **kwargs)
1040 # Do some checks on the args provided
1041 if sum(1 for arg in (step, num, breakpoints) if arg is None) > 1:
-> 1042 raise ValueError(f"Only one of ('step', 'num', 'breakpoints') should be passed.")
1043
1044 # If no axis is provided, let's get the first one that is not displayed
ValueError: Only one of ('step', 'num', 'breakpoints') should be passed.
Ok, now it starts to make sense… but looking at the help message is a bit tedious, don’t you think?
Yes, I agree. The plan is to have an individual notebook to showcase the abilities of each plot, because, you know, we came here to visualize. But we’re not quite there yet, sorry.
Btw… why did an animation come out of nowhere?
Magic doesn’t exist, so of course someone has developed it.
I’m sure it’s complicated as hell to use. This is why you’ve been hiding it from us…
Well, you can judge for yourself.
[8]:
from sisl.viz import Animation, BandsPlot
bands_file = siesta_files / "SrTiO3.bands"
# There are two main ways to build an animation for yourself
# You can either provide already initialized plots to Animation
plots = [ Plot(bands_file, bands_color=color) for color in ("green", "orange", "red")]
from_animation = Animation(plots=plots)
# Or use the animated class method
from_animated = BandsPlot.animated(
"bands_color", ("green", "orange", "red"), # Animate the bands_color setting with this values
fixed = {"bands_file": bands_file}, # Keep this settings fixed for all frames
)
# Show them both
from_animation.show()
from_animated.show()
Frames are not supported by the plotly.graph_objs.FigureWidget class.
Note: Frames are supported by the plotly.graph_objs.Figure class
Frames are not supported by the plotly.graph_objs.FigureWidget class.
Note: Frames are supported by the plotly.graph_objs.Figure class
So, you basically get the same animation in both cases. But is it really the same?
[9]:
# Let's save them
from_animation.save("From_animation.plot")
from_animated.save("From_animated.plot")
[9]:
True
If you go to the directory where this tutorials are and you run the command ll -h you will see the following (moreless): - From_animated.plot weights 679 KB - From_animation.plot weights 855 KB
I’ll give you a moment to solve the mistery…
That’s right! Animation has detected that some data can be shared between plots and it is doing so.
But how?!
Again, settings. It’s always about settings.
But you must know that this is a crucial feature for plots with larger data, like the charge density scan we saw previously. In that case, your computer might not even be able to sustain such HUGE quantities of data. Therefore, there is a template_plot keyword that you can provide to both animated and Animation to explicitly set the plot that will share data.
By the way, here’s a cell for you to check that I’m not lying, try checking the shared attribute of the plot that came from the animated method.
[ ]:
Ok, I see. Can you tell us how to load the plots that you saved there?
Sure:
[10]:
from sisl.viz import load
#load("I know you have an intuition of what to put here")
Thanks, but what’s the point of saving them anyway?
Well, you can: - Open them later and they will already contain all the data. - Share it with other people easily.
However, if you just want to share the plot and not the data, you have beter and more lightweight options: - Save it as a picture (you probably already saw the picture icon that appears when you hover the plot at the top-right corner) - Save it as html using the .html() method: Great for keeping functionality and vital for animations. - Take the figure attribute and save it however you want.
This last point brings me to a breakpoint in our relation. I have to make a confession: I haven’t developed the figures themselves, these areplotlyfigures.
Aha! I knew there was something you were hiding.
Yes, indeed. I was hiding that, since Plot is an extension of plotly Figure, all plotly methods are available to you to postprocess the plot that you obtained as you wish:
[11]:
# Let's build a plot
plot = Plot(siesta_files / "SrTiO3.RHO", axes=[0,1], nsc=[2,1,1], zsmooth="best", title="The importance of the green line")
# And now let's draw a line a line indicating something super important
# using the plotly add_scatter method on our figure
plot.add_scatter(x=[0,4], y=[1,3],line_width=5, line_color="lightgreen", showlegend=False)
Now you got a taste of the basic things that you should expect from sisl’s visualization module. We hope that you liked what you saw :)
If you are willing to know more, please keep on reading the notebook. We appreciate your interest and we are definitely willing to show more. And we honestly think you won’t regret it.
Let’s talk about settings¶
Finally!
Life is unpredictable.
And that’s why needing to define all the parameters of your plot on initialization seems like too much to ask. That’s why, we’ve separated the work of our plots into three main processes:
Reading the data.
Processing the data.
Displaying the figure.
At this point, you probably already see that there is clearly at least one step that you don’t want to be doing all the time: Reading your 300MB file.
I get it, I can run different steps to update my plot as I need. But how would I know, if it was not me that developed the plot? Do I have to look into the code of each plot?!
No, that’s the point of settings. Plots have settings (as you have previously discovered, I know what you did in that cell…). And plots know which settings are run in each step of the process. So, when you update a setting, don’t worry, they will know what to do.
And how do I “update a setting”?
[12]:
# Get the bands plot
plot = Plot(siesta_files / "SrTiO3.bands")
# If you don't know what are the settings that you can change, print the plot
# print(plot)
# But I already know, so I will update them using the update_settings method
plot.update_settings(Erange=[-5,5], gap=True)
And what if I messed up the plot with the new settings?
[13]:
plot.undo_settings()
The undo_settings() method even has a nsteps keyword that will allow you to go way back. No one will ever know about your “little experiments”.
Monitoring changes¶
Plots can keep track of the files that they read.
Using this, you can check if there are updates available for a given plot very easily.
[14]:
plot = Plot(siesta_files / "SrTiO3.bands")
plot.updates_available()
[14]:
False
Of course there are no available updates, you just read the file…
Yeah, thanks.
Do I have to be checking for updates until there is one? That’s pointless.
Well, you can, sure, if you want. But of course there is a method already there for you.
Let’s build a different plot that makes sense tracking.
[15]:
from sisl.viz import ForcesPlot
forces = ForcesPlot(out_file="../files/water/water.out")
The plot has been initialized correctly, but the current settings were not enough to generate the figure.
(Error: Could not read or generate data for ForcesPlot from any of the possible sources.
Here are the errors for each source:
- siesta_output: FileNotFoundError.[Errno 2] No such file or directory: '../files/water/water.out' )
Oops! Seems that these plots are not that great after all.
We are trying to make a plot out of a file that doesn’t even exist. So, the error is fair enough.
Although it does not yet exist, Lets make the plot listen for updates:
[16]:
forces.listen()
Wow, impressive. Seems like it didn’t do much…
Well, that’s the point of the listen method. It runs asyncronously. This means that it does not block the execution of other code. It basically means that, while this plot is listening for updates, you can continue doing things on the notebook.
But enough talk, let’s see it working. Go to the files/water folder and execute siesta so that it sends the output to a file called water.out:
siesta < water.fdf > water.out
Let’s see what happens…
Did you see how the plot was changing? The plot does not know when to stop listening. Who knows, maybe an update will come sometime. Let’s take a moment to stop it.
[17]:
forces.stop_listening()
You probably saw that the updating process didn’t look great. That is because we need to clear the output and plot the figure again each time.
So classy…
Well, the plot is only doing that because it does not find the appropiate jupyter notebook widgets. Check which widgets are you missing:
[18]:
forces._widgets
[18]:
{'plotly_avail': True,
'plotly_error': False,
'events_avail': False,
'events_error': False,
'plotly': True,
'events': False}
If you have plotly available but it indicates an error, it is probably because, although you are in your environment’s kernel, you are running jupyter notebook from a different environment.
Just run the notebook from your environment, or uncomment this cell and run it (don’t remove the !) to install plotly also in the environment that you are running the notebook.
[19]:
#!pip3 install plotly
Then close and open the jupyter server again with jupyter notebook or however you do it (restarting the kernel is not enough).
Regarding events, it is a widget that will provide you with the ability to use keyboard shortcuts on the plots. It can be very handy, but if you don’t want it, that’s fine.
If you want to have it:
[20]:
#!pip3 install ipyevents
#!jupyter nbextension enable --py --user ipyevents
Or with conda:
[21]:
#!conda install -c conda-forge ipyevents
If you installed event, let’s take a moment to see if it works.
Close the server and open it again with jupyter notebook or however you like to do it (restarting the kernel is probably not enough).
[22]:
plot = Plot(siesta_files / "SrTiO3.RHO")
plot.show()
Try to play with it and see if it works.
Place your mouse on top of the plot and press any key. You should see it logged in the left-down corner.
Then press shift+? to see all the available shortcuts for this plot. Try to use them. If you’ve gotten here, there should be no problem now :)
Fun part is that you don’t need to stick to the shortcuts that are provided by default, you can build your own so that it fits perfectly your requirements. More on this in upcoming tutorials. But feel free to add a little pressure so that we do it faster, we will appreciate your enthusiasm for sure.